﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Windows.Threading;

namespace Milkify.Input
{
    public class CompositeCommand : ICommand
    {
        private readonly string mName;
        private readonly List<ICommand> mCommands = new List<ICommand>();
        private readonly Dispatcher mDispatcher;

        public CompositeCommand(string name)
        {
            mName = name;
            mDispatcher = App.Current.Dispatcher;
        }

        public virtual void RegisterCommand(ICommand command)
        {
            lock (this)
            {
                if (!mCommands.Contains(command))
                {
                    mCommands.Add(command);
                    command.CanExecuteChanged += new EventHandler(Command_CanExecuteChanged);
                    OnCanExecuteChanged(EventArgs.Empty);
                }
            }
        }

        public virtual void UnregisterCommand(ICommand command)
        {
            lock (this)
            {
                if (mCommands.Remove(command))
                {
                    command.CanExecuteChanged -= new EventHandler(Command_CanExecuteChanged);
                    OnCanExecuteChanged(EventArgs.Empty);
                }
            }
        }

        protected virtual void OnCanExecuteChanged(EventArgs e)
        {
            if (CanExecuteChanged != null)
            {
                if (mDispatcher.CheckAccess())
                {
                    CanExecuteChanged(this, e);
                }
                else
                {
                    mDispatcher.BeginInvoke(DispatcherPriority.Normal, (Action<EventArgs>)OnCanExecuteChanged, e);
                }
            }
        }

        private void Command_CanExecuteChanged(object sender, EventArgs e)
        {
            OnCanExecuteChanged(EventArgs.Empty);
        }

        #region ICommand Members

        public event EventHandler CanExecuteChanged;

        public virtual bool CanExecute(object parameter)
        {
            lock (this)
            {
                foreach (var command in mCommands)
                {
                    if (!command.CanExecute(parameter))
                        return false;
                }
            }
            return true;
        }

        public virtual void Execute(object parameter)
        {
            if (CanExecute(parameter))
            {
                lock (this)
                {
                    foreach (var command in mCommands)
                    {
                        command.Execute(parameter);
                    }
                }
            }
        }

        #endregion
    }
}
